﻿using System;
using System.Collections.Generic;
using System.Linq;
using Styx;
using Styx.CommonBot;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace HolySword.Helpers
{
    public static class TargetManager
    {
        private static WoWUnit EnsureUnitTargeted
        {
            get
            {
                if (StyxWoW.Me.CurrentTarget == null && StyxWoW.Me.Combat)
                    FindAggroTarget();
                else FindBestTarget(35);
                return null;
            }
        }

        public static Composite NeedTarget()
        {
            return
                new Decorator(
                    ret =>
                    StyxWoW.Me.CurrentTarget == null || StyxWoW.Me.CurrentTarget.IsDead,
                    new Decorator(ret => true,
                                  new Action(ret =>
                                  {
                                      try { EnsureUnitTargeted.Target(); }
                                      catch (Exception) { }
                                  })
                        )
                    );
        }

        public static void NeedHealTarget()
        {
            NeedHealTarget(40);
        }

        public static void NeedHealTarget(double withinDist)
        {
            WoWUnit newTarget = (from o in ObjectManager.ObjectList
                            where o is WoWUnit
                            let unit = o.ToUnit()
                            where
                                unit.Distance <= withinDist
                                && unit.IsAlive
                                && unit.InLineOfSpellSight
                                && !unit.IsPet
                                && !Blacklist.Contains(unit.Guid)
                            orderby unit.CurrentHealth ascending
                            select unit
                        ).FirstOrDefault();

            // now make best selection from list
            SafeSetCurrentTarget(newTarget); 
        }

        private static void SafeSetCurrentTarget(WoWUnit target)
        {
            if (target == null)
                StyxWoW.Me.ClearTarget();
            else if (!StyxWoW.Me.GotTarget || StyxWoW.Me.CurrentTarget.Guid != target.Guid)
                target.Target();
        }

        private static bool HasAggro(WoWUnit unit)
        {
            return
                unit.Combat
                && unit.Attackable
                && !unit.IsDead
                && !unit.IsFriendly
                && (unit.Aggro || unit.PetAggro || unit.IsTargetingMeOrPet);
        }

        private static bool IsPvp()
        {
            return Battlegrounds.IsInsideBattleground;
        }

        private static bool IsMeOrMyStuff(WoWUnit unit)
        {
            if (unit == null)
                return false;
            // find topmost unit in CreatedByUnit chain
            while (unit.CreatedByUnit != null)
                unit = unit.CreatedByUnit;
            // check if this unit was created by me
            return unit.IsMe;
        }

        // find any units with aggro to us (keeping us in combat)
        // ... should work for totems also
        private static void FindAggroTarget()
        {
            List<WoWUnit> mobs = (from o in ObjectManager.ObjectList
                                  where o is WoWUnit
                                  let unit = o.ToUnit()
                                  where unit.IsTargetingMeOrPet &&
                                        !Blacklist.Contains(unit.Guid) &&
                                        StyxWoW.Me.Location.Distance(unit.Location) <= (40 * 40)
                                  orderby unit.CurrentHealth ascending
                                  select !IsMeOrMyStuff(unit) ? unit : unit.CurrentTarget
                                 ).ToList();

            if (!mobs.Any()) return;
            WoWUnit newTarget = mobs.First();
            if (newTarget.IsPet)
                newTarget = newTarget.CreatedByUnit ?? (newTarget.OwnedByUnit ?? newTarget);
            SafeSetCurrentTarget(newTarget);
        }

        private static void FindBestTarget(double withinDist)
        {
             WoWUnit newTarget = (from o in ObjectManager.ObjectList
                            where o is WoWUnit
                            let unit = o.ToUnit()
                            where
                                unit.Distance <= withinDist
                                && unit.Attackable
                                && unit.IsAlive
                                && unit.InLineOfSpellSight
                                && !IsMeOrMyStuff(unit)
                                && !unit.IsPet
                                && !Blacklist.Contains(unit.Guid)
                            orderby unit.CurrentHealth ascending
                            select unit
                        ).FirstOrDefault();

            // now make best selection from list
            SafeSetCurrentTarget(newTarget);
        }
    }
}